home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Libraries / c++advio 2.3 / Advanced i⁄o / README < prev    next >
Encoding:
Text File  |  1997-03-06  |  11.3 KB  |  297 lines  |  [TEXT/ttxt]

  1.            Service C++ functions and classes
  2.     dealing mostly with "advanced" i/o and the arithmetic compression
  3.  
  4. ***** For the version history, read on
  5.  
  6. ***** Comments/questions/problem reports/etc
  7. are all very welcome. Please send them to me at
  8. oleg@pobox.com or oleg@acm.org
  9.  
  10. ***** Platforms
  11.     I have personally compiled and tested the C++ advanced
  12. iostream libraries on the following platforms:
  13.     SunSparc20/Solaris 2.4, gcc 2.7.2, libg++ 2.7.1
  14.     SunSparc20/Solaris 2.3, SunPro C++ compiler
  15.     HP 9000/{750,770,712}, HP/UX 9.0.5, 9.0.7 and 10.0,
  16.                 gcc 2.7.2, libg++ 2.7.2
  17.     PowerMac 7100/80, 8500/132,
  18.     Metrowerk's CodeWarrior C++, v. 7 - 11
  19.     Intel, Windows95, Borland C++ 4.5/5.0
  20.     (the binaries then ran under Windows NT 4.0 beta)
  21. I know that the packages also work on DEC Alpha, FreeBSD,
  22. and Concurrent Maxion 8000/RTU 6.2V25 (all with gcc 2.7.2 compiler)
  23.  
  24. ***** Verification files: vmyenv, vendian_io, vhistogram, varithm
  25.  
  26. Don't forget to compile and run them, see comments in the Makefile for
  27. details.  The verification code checks to see that all the functions
  28. in this package have compiled and run well. The code also can serve as
  29. an example how package's classes/functions can be used
  30.  
  31.  
  32. ***** Highlights and idioms
  33.  
  34. ---- Extended file names
  35.  
  36. The package adds support for "extended" file names with pipes in them.
  37. That is, the name of a file to open may be specified now as "|
  38. command" or "command |" i.e. as a pipe. For example,
  39.     EndianIn istream;
  40.     istream.open("gunzip < /tmp/aa.gz |");
  41.     EndianOut stream("| compress > /tmp/aa.Z");
  42.     image.write_pgm("| xv -");
  43. The <command> is launched in a subprocess through '/bin/sh' with its
  44. standard input/output hooked, through pipe(), to the file being
  45. opened.
  46.  
  47. This extension is implemented on the lowest possible level, right
  48. before the request to open a file goes to OS (through the system call
  49. open(2)). A function sys_open() (in the source file sys_open.cc) acts
  50. as a "patch": that is, if you call sys_open() instead of open() to
  51. open a file, you get all the open() functionality plus the extended
  52. file names.
  53.  
  54. Thus, some libg++ 2.7.2 iostream functions were modified to call
  55. sys_open() instead of open(). If one wants to use the extended file
  56. names outside gcc/libg++, he needs to do open->sys_open substitution
  57. himself.
  58.  
  59.  
  60. ---- Explicit Endian I/O of short/long integers
  61.  
  62.   EndianOut stream("/tmp/aa");
  63.   stream.set_littlendian();
  64.   stream.write_long(1);
  65.  
  66. That means, 1 would be written as a long integer with the least
  67. significant byte first, NO MATTER which computer (computer
  68. architecture) the code is running on. Using explicit endian
  69. specification (like above) is the only way to ensure portability of
  70. binary files containing arithmetic data.
  71.  
  72.  
  73. ---- Stream sharing
  74.  
  75. EndianIn/Out streams can share the same i/o buffer. This is useful
  76. when one needs to read/write a "stratified" (layered) file consisting
  77. of various variable-bit encoded data interspersed with headers.  For
  78. example, a file may begin with a header (telling the total number of
  79. data items, normalization factors) followed by some variable-bit
  80. encoding of items, followed by another header, followed by an
  81. arithmetic compressed stream of data, etc. Thus, a file can be like a
  82. waffle pie, made of many layers: each of them being interpreted using
  83. different streams, each of them collectively sharing the same file and
  84. the same file pointer. The situation is similar to sharing an open
  85. file (and a file pointer) among parent and child (forked) processes.
  86.  
  87. Note that merely opening a stream on a dup()-ed file handle, or
  88. sync()-ing the stream doesn't cut it entirely. See endian_io.cc for
  89. more discussion. The bottom line is, this package implements stream
  90. sharing in a safe and portable way: it works on a Mac just as well as
  91. on different flavors of UNIX.
  92.  
  93. ---- Simple variable-length coding of short integers
  94.  
  95. The code is intended for writing a collection of short integers where
  96. many of them are rather small in value; still, big values can crop up
  97. at times, so we can't limit the size of the code to anything less than
  98. 16 bits.  The code is a variation of a start-stop code described in
  99. Appendix A, "Variable-length representations of the integers" of the
  100. "Text Compression" book by T.Bell, J.Cleary and I.Witten,
  101. p.290-295. The present code features support for both negative and
  102. positive numbers and an optimization based on the fact that all
  103. numbers are no larger than 2^15-1 in abs value, and an assumption that
  104. most of them are smaller than 512 (in absolute value).
  105.  
  106.  
  107. ---- Arithmetic compression of a stream of integers
  108.  
  109. The present package provides a clean C++ implementation of Bell,
  110. Cleary and Witten's arithmetic compression code, with a clear
  111. separation between a model and the coder. ArithmCodingIn /
  112. ArithmCodingOut act as i/o streams that encode signed short integers
  113. you put() to, and decode them when you get() them. The
  114. ArithmCodingIn/Out object needs a "plug-in" of a class
  115. Input_Data_Model when the stream is created. The Input_Data_Model
  116. object is responsible for providing the codec with the probabilities
  117. (frequencies) a given data item is expected to appear with, and for
  118. finding a symbol given its cumulative frequency. Input_Data_Model may
  119. also modify itself to account for a new symbol. Thus, the ArithmCoding
  120. class is a sort of the 'iostream' class that writes/reads data items
  121. to/from the stream performing encoding/decoding. It relies upon the
  122. Input_Data_Model for the probabilities needed to perform the
  123. arithmetic coding.
  124.  
  125. The current version of the package provides two Input_Data_Model
  126. plug-ins, both performing adaptive "modeling" of a stream of
  127. integers. The first plug-in uses a simple 0-order adaptive prediction
  128. (like the model given in the Witten's book). The other one takes a
  129. histogram to sketch the initial distribution, and is a bit
  130. sophisticated in updating the model. It is used in compressing a
  131. wavelet decomposition of an image. The code below (taken literally
  132. from varithm.cc) demonstrates how the coder classes are actually used.
  133.  
  134. The first example writes two different streams (of different patterns,
  135. that's why it was better to encode them separately) into the same file
  136.  
  137.   EndianOut stream("/tmp/aa");
  138.   stream.set_littlendian();
  139.   const int sample_header = 12345;
  140.   {
  141.     AdaptiveModel model(-1,4);
  142.     ArithmCodingOut ac(model);
  143.     ac.open(stream);
  144.     for(i=0; i<sizeof(pattern1)/sizeof(pattern1[0]); i++)
  145.       ac.put(pattern1[i]);
  146.   }
  147.   {
  148.     stream.write_long(sample_header);    // write a "header"
  149.     AdaptiveModel model(-1,4);        // followed by the arithmetic coded
  150.     ArithmCodingOut ac(model);        // stream
  151.     ac.open(stream);
  152.     for(i=0; i<sizeof(pattern2)/sizeof(pattern2[0]); i++)
  153.       ac.put(pattern2[i]);
  154.   }
  155.   stream.close();
  156.  
  157. The reading is similar.
  158.  
  159. The second example uses a different model plug-in, yet i/o is similar
  160.  
  161. static void test_adh(void)
  162. {
  163.   message("\nCreating Histogram ...\n");
  164.   Histogram histogram(-7,7);
  165.   register int i;
  166.   for(i=0; i<MyPattern_size; i++)
  167.     histogram.put(MyPattern[i]);
  168.  
  169.   message("\nWriting data ...");
  170.   AdaptiveHistModel model(histogram);
  171.   ArithmCodingOut ac(model);
  172.   ac.open("/tmp/aa");
  173.   for(i=0; i<MyPattern_size; i++)
  174.     ac.put(MyPattern[i]);
  175.   ac.close();
  176.  
  177.   message("\nCoded file /tmp/aa has been created\n");
  178.  
  179.   AdaptiveHistModel i_model;
  180.   ArithmCodingIn ac1(i_model);
  181.   ac1.open("/tmp/aa");
  182.   for(i=0; i<MyPattern_size; i++)
  183.   {
  184.     register int val_read = ac1.get();
  185.     if( val_read != MyPattern[i] )
  186.       _error("Read value %d of the %d-th integer is not what it is "
  187.          "supposed to be, %d",
  188.          val_read, i, MyPattern[i]);
  189.   }
  190.   ac1.get();
  191.   assert( ac1.is_eof() );
  192. }
  193.  
  194. ---- Convenience Functions
  195.  
  196. The package defines a few functions I found convenient to use, like
  197. message(...) (which is equivalent to fprintf(stderr,....))  and
  198. _error(...) ( the same as message(...), abort();). One doesn't need to
  199. to #include <stdio.h> to use them.
  200.  
  201. Also included:
  202.   xgetenv()            - getenv() with a fall-back clause
  203.   get_file_size()      - also with a default clause
  204.   does_start_with_ci() - an amazingly useful function in input parsing
  205. see vmyenv.cc for examples of their usage.
  206.  
  207. The validation file vmyenv.cc also illustrates how to catch an abort
  208. condition, without crashing the main process (macro
  209. must_have_failed())
  210.  
  211.  
  212. ---- Portability Tips
  213.  
  214. Borland C++ 4.5 is sometimes unhappy with the order BitIn, BitOut (in
  215. endian_io.h) and ArithmCodingIn, ArithmCodingOut (in arithm.h) classes
  216. are derived.  Right now,
  217.     class BitIn : BitIOBuffer, public EndianIn
  218. upsets BC because "RTTI class BitIn being derived from non-RTTI class
  219. BitIOBuffer". I have a hunch that the error like that could be avoided
  220. by tinkering with C++ compiler options. On the other hand, merely
  221. switching the order of inheritance,
  222.         class BitIn : public EndianIn, BitIOBuffer
  223. solves the problem. The same for BitOut, ArithmCodingIn, and
  224. ArithmCodingOut.
  225.  
  226.  
  227.  
  228. ***** Grand plans
  229.  
  230. ***** Revision history
  231.  
  232. Version 2.3 - Mar 1997
  233.     - added xgetenv(), does_start_with_ci(), get_file_size()
  234.     - created vmyenv.cc to validate myenv.h's functions
  235.     - a few adjustments (mainly to endian_io.h and arithm.h)
  236.       to account for changes in implementation (and interfaces,
  237.       <sigh>) of the C++ iostream library, made in new versions
  238.       of libg++ (v. 2.7.2) and Metrowerk's CodeWarrior (v. 11)
  239.       This brings c++advio closer to the (ever evolving) C++ standard.
  240.     - _Vocabulary_ (an embedded language, actually) is now
  241.       distributed with the c++advio, see voc.h for more detail.
  242.  
  243. Version 2.2.3 - Mar 1996
  244.     - sys_open.cc now accepts an input pipe with more than one link
  245.       as a "file" name
  246.     - endian_io.*: added EndianIOData:unshare() method to break
  247.       sharing of a streambuffer (if was any). This method is intended
  248.       for destructors only (makes the code more portable).
  249.     - careful attention to comparisons between signed and unsigned
  250.       (mainly to get gcc 2.7.2 to shut up)
  251.     - now everything compiles with gcc 2.7.2/libg++ 2.7.1 and
  252.       Metrowerks Codewarrior 8.
  253.     - portability tweaks in myenv.h (declaring bool for platforms
  254.       that lack it)
  255.     - arithm_modadh.*: more logical (and efficient) way of "pulling-to-
  256.       the-front" when updating adaptive model frequency counters
  257.       by more than 1. Also, the initial distribution is slightly
  258.       tweaked. The upshot is that the compression is a tiny bit
  259.       better (at least, the algorithm makes more sense).
  260.  
  261. Version 2.2.1 - Jun 1995
  262. Fixed the last remaining incompatibility glitches. Now, exactly the
  263. same code compiles on a Mac with CodeWarrior 6 and on Unix with gcc
  264. 2.6.3
  265.  
  266. Version 2.2 - May 1995
  267. Added a variable-length (start/stop) coding of signed short integers.
  268. Added dealing with simple histograms of an integer-valued
  269. distribution.
  270.  
  271. Version 2.1 - Mar 1995
  272. Introducing bool where appropriate (instead of int) and adding checks
  273. to make sure an EndianIn/Out stream was opened successfully.
  274.  
  275. Version 2.0 - Feb 1995
  276. Big change: splitting EndianIO into EndianIn and EndianOut and
  277. removing all libg++-specific things; everything should be very
  278. portable now.  Making sharing of the streambuffer portable.
  279.  
  280. Version 1.4 - Feb 1994
  281. Updated for libg++ 2.5.3
  282.  
  283. Version 1.3 - Aug 1993
  284. Introducing attachment of one stream to another, or sharing of a
  285. streambuf among several streams. Took care of properly terminating an
  286. arithm coding stream by writing a few phony bits at the end (so we
  287. won't hit the EOF on reading). Thus it is possible now to concatenate
  288. arithmetic coding streams.
  289.  
  290. Version 1.2 - Jun 1992
  291. Updated to compile under gcc/g++ 2.2.1 and work with libg++ 2.0. The
  292. first implementation of the arithmetic coding package
  293.  
  294. Version 1.1 - Nov 1991 - May 1992
  295. Initial revision
  296.  
  297.